#include "include/businessService.hpp"
#include "include/MySQLClient.hpp"
#include "include/TLV.hpp"
#include "include/UserMannger.hpp"
#include "include/TLVPacket.hpp"
#include "include/ffmpeg.hpp"
#include "include/Curl.hpp"
#include "include/videorecoded.hpp"
#include <nlohmann/json.hpp>
#include <random>
#include <string>
#include <nlohmann/json.hpp>
#include <thread>
#include <unordered_set>
using std::atoi;
using std::thread;
using json = nlohmann::json;
using std::unordered_set;

auto users = UserMannger::getUseMananger();

void UserLoginSection1::process(void *ptr){
    string sql("select * from users where u_name = ");
    sql += "'"+this->_packet._msg+"'";
    MySQLClient SQLConn;
    vector<vector<string>>  data =  SQLConn.readOperationQuery(sql);
    SQLConn.dump(data);
    if(data.size() < 2){
        char value[1]={0};
        TLV tlv(TTLS1RPERR,0,value);
        string msg(reinterpret_cast<char *>(&tlv),8+0);
        _conn.sendInLoop(msg);
    }else{
        TLV tlv(TTLS1RPOK,data[1][3].size(),data[1][3].c_str());
        string msg((char*)&tlv,data[1][3].size()+8); 
        User user;
        user._channel = _conn.shared_from_this();
        user._setting = data[1][3];
        user._status= USER_IS_LOGING;
        user._encrypted = data[1][2];
        user.id = atoi(data[1][0].c_str());
        user._name = data[1][1];
        users->addUser(_conn.fd(),user);
        cout<<"respone msg :  "<<msg<<endl;
        _conn.sendInLoop(msg);
        //_conn.send(msg);
    }
}

void UserLoginSection2::process(void *ptr){
    User * curUser = users->getUser(_conn.fd());
    if(curUser->_encrypted == _packet._msg){//判断加密后的密码是否一致
                                            //返回登入成功的消息
        string sql(R"(
        SELECT 
            c.camera_id,
            c.camera_type,
            c.camera_serial_no,
            c.camera_channels,
            c.camera_ip,
            c.rtmp
        FROM camera c
        JOIN client_cameras cc ON c.camera_id = cc.camera_id
        JOIN users u ON cc.client_id = u.u_id
        WHERE u.u_id = )"); 

        //改变用户的连接的登入状态
        User * user = users->getUser(_conn.fd());
        user->_status = USER_HAS_LOGED;
        sql += to_string(user->id) ;
        LOG_INFO(sql.c_str());
        // 创建对象数组（每个对象都有命名字段）
        json j_array = json::array(); // 创建空数组
        MySQLClient SQLConn;
        vector<vector<string>>  data =  SQLConn.readOperationQuery(sql);
        SQLConn.dump(data);
        std::vector<std::string> fieldNames = {"camera_id", "camera_type", "camera_serial_no","camera_channels","camera_ip","rtmp"};
        for(int i = 1;i<(int)data.size();++i){
            json obj = json::object();
            for(int j = 0;j<(int)data[0].size();++j ){
                obj[fieldNames[j]] = data[i][j];
            }
            j_array.push_back(obj);
        }

        LOG_INFO(j_array.dump(2).c_str());

        TLVPacket tlv(TTLS2RPOK,j_array.dump().c_str()) ;
        string temp("登入成功");
        LOG_DEBUG(temp.c_str());
        vector<uint8_t> sdv = tlv.serialize();
        //cout<< "send size is ："<<j_array.dump()<<endl; 
        _conn.sendInLoop(string((const char *)sdv.data(),sdv.size()));
    }else{
        char value[1]={0};
        TLV tlv(TTLS2RPERR,0,value);
        string msg(reinterpret_cast<char *>(&tlv),8+0);
        //改变用户的连接的登入状态
        User * user = users->getUser(_conn.fd());
        user->_status = USER_NO_LOG;
        _conn.sendInLoop(msg);

    }
}

//MD5生成8个字符
string UserRegister1::GenRandomString(int length){
    int flag;
    string salt(length+1,'\0');
    srand((unsigned)time(nullptr));
    for(int i =0;i< length;++i){
        flag = rand()%3;
        switch(flag){
        case 0: salt[i]='A' + rand() % 26;break;
        case 1: salt[i]='a' + rand() % 26;break;
        case 2: salt[i]='0' + rand() % 10;break;
        default:salt[i] = 'x';break;
        }
    }
    return salt;
}

void UserRegister1::process(void *prt){
    //先去数据库中查找是否有
    string sql("select * from users where u_name = ");
    sql += "'"+this->_packet._msg+"'";
    MySQLClient SQLConn;
    vector<vector<string>>  data =  SQLConn.readOperationQuery(sql);
    SQLConn.dump(data);
    if(data.size() >= 2){
        char value[1]={0};
        TLV tlv(TTR1RPERR,0,value);
        string msg(reinterpret_cast<char *>(&tlv),8+0);
        _conn.sendInLoop(msg);//数据库有该账号不需要注册所以注册失败了
    }else{
        //数据库中没有该数据，经行注册
        //此时应该存对该连接用来注册的用户名
        User user;
        user._name = _packet._msg;
        string debugMsg("用户发起注册请求,u_name: "+user._name);
        LOG_DEBUG(debugMsg.c_str());
        user._channel = _conn.shared_from_this();
        user._status = USER_NO_LOG;
        string setting;//使用md5加密方式进行加密
        string salt;
        salt = this->GenRandomString(saltLen);
        setting =preWay+ salt;//发送客户端的setting 值完成
        user._setting=setting;
        debugMsg = "随机生成的setting: "+setting;
        LOG_DEBUG(debugMsg.c_str());
        users->addUser(_conn.fd(),user);//完成连接和user的绑定
        TLV tlv(TTR1RPOK,setting.size()+8,setting.c_str());
        string msg(reinterpret_cast<char *>(&tlv),8+setting.size());
        _conn.sendInLoop(msg);
    }
}
void UserRegister2::process(void *prt){
    //该任务只赋值存储这个连接发送来的注册的user
    User * puser = users->getUser(_conn.fd());
    puser->_encrypted = _packet._msg;
    string debugMsg("用户完成密码加密,_encrypted: "+puser->_encrypted);
    //写入数据库当中
    char sql[255]={0};
    sprintf(sql,"INSERT INTO users(u_name, u_password_hash, setting, registration_date, updated_at) value('%s','%s','%s',now(),now())",puser->_name.c_str(),puser->_encrypted.c_str(),puser->_setting.c_str());
    MySQLClient sqlConn;
    sqlConn.writeOperationQuery(string(sql));
    users->delUser(_conn.fd());//删除usermananger被管理的用户

    //封装当前返回的消息
    char value[1]={0};
    TLV tlv(TTR2RPOK,0,value);
    string msg(reinterpret_cast<char *>(&tlv),8+0);
    _conn.sendInLoop(msg);//成功注册

}

void SendCodecParams::process(void * ptr){
    string channel = string(_packet._msg[_packet._length-1],1);
    string rtmp = string(_packet._msg.c_str(),_packet._length-1);
    string sql = "SELECT DISTINCT  b.client_id AS user_id FROM camera c JOIN client_cameras b ON c.camera_id = b.camera_id WHERE c.rtmp =  ";
    sql += "'" +rtmp +"'";
    LOG_INFO(sql.c_str());
    MySQLClient SQLConn;
    vector<vector<string>>  data =  SQLConn.readOperationQuery(sql);//查找用户 id 
    SQLConn.dump(data);

    pair<string,string> pair_string  = RtspDecoder::recvAVCodecParameters(_packet._msg); 
    TLVPacket tlv( TASK_GET_CODEC_PARAMS_RESP_OK,pair_string.first);
    vector<uint8_t> st_data = tlv.serialize();
    _conn.sendInLoop(string((const char *)st_data.data(),st_data.size()));
    TLVPacket atlv( TASK_GET_AUDIO_CODEC_PARAMS_RESP_OK,pair_string.second);
    vector<uint8_t> ast_data = atlv.serialize();
    _conn.sendInLoop(string((const char *)ast_data.data(),ast_data.size()));
    /*if(data.size()<2){

      char value[1]={0};
      TLV tlv( TASK_GET_CODEC_PARAMS_RESP_ERROR,0,value);
      string msg(reinterpret_cast<char *>(&tlv),8+0);
      _conn.sendInLoop(msg);
      }else{
      unordered_set<int> user_ids;
      for(int i = 1;i<data.size();++i){
      user_ids.emplace(std::atoi(data[i][0].c_str()));
      }
      for(auto & elemt : users->getUsers()){
      if(user_ids.count(elemt.second.id)>0){
      string value = RtspDecoder::recvAVCodecParameters(_packet._msg); 
      TLVPacket tlv( TASK_GET_CODEC_PARAMS_RESP_OK,value);
      vector<uint8_t> st_data = tlv.serialize();
      _conn.sendInLoop(string((const char *)st_data.data(),st_data.size()));
      return; 
      }
      }
      }

      char value[1]={0};
      TLV tlv( TASK_GET_CODEC_PARAMS_RESP_ERROR,0,value);
      string msg(reinterpret_cast<char *>(&tlv),8+0);
      _conn.sendInLoop(msg);
      */
}

void SendAVPacket::process(void * ptr){
    int fdIndex = _conn.fd(); 
    _rtspd->sendAVpacket(_conn);
    _ffmpegs.erase(fdIndex);
}

using json = nlohmann::json;
bool is_valid_json(const std::string& json_str) {
    try {
        auto json = nlohmann::json::parse(json_str);
        return true;
    } catch (const nlohmann::json::parse_error& e) {
        return false;
    }
}
void SendPTZControl::process(void *ptr){
    Curl scurl;//自定义封装的url使用类
    string response = scurl.get(_packet._msg);
    cout<<"response : "<< response<<endl;
    //返回值代码进行比较
    if(is_valid_json(response)==1){
        json j = json::parse(response);
        int code = j["code"].get<int>();
        cout<<"code : "<<code<<endl;
        int num_code = code;
        if(num_code == 0){
            char value[1]={0};
            TLV tlv(TASK_PTZ_CONTROL_RESP_OK,0,value);
            string msg(reinterpret_cast<char *>(&tlv),8+0);
            _conn.sendInLoop(msg);
            return;
        }
    }
    //如果代码返回不正确就直接返回失败
    char value[1]={0};
    LOG_WARN("PTZ control losed");
    TLV tlv(TASK_PTZ_CONTROL_RESP_ERROR,0,value);
    string msg(reinterpret_cast<char *>(&tlv),8+0);
    _conn.sendInLoop(msg);

}


void RecordVideo::process(void * ptr){
    recorded(_url,_cameraId,_channel,_camera_serial_no);
}

const int time_rate = 1000; 

void SendPlayList::process(void *prt ){
    if(is_valid_json(_packet._msg)==1){
        json j =json::parse(_packet._msg);
        LOG_INFO(_packet._msg.c_str());
        long start_time = j["start_time"].get<long>()*1000;
        long end_time = j["end_time"].get<long>()*1000;
        int camera_id = j["camera_id"].get<int>();
        int channel = j["channel"].get<int>();
        //查找数据库中对应的数据
        char sql[256]={0};
        sprintf(sql,"SELECT start_time,end_time FROM record_file  WHERE camera_id = %d AND start_time >= %ld AND end_time <= %ld AND channel = %d",camera_id,start_time,end_time,channel);
        LOG_DEBUG(sql);
        MySQLClient SQLConn;
        vector<vector<string>> data = SQLConn.readOperationQuery(sql);
        if(data.size()<2){
            char value[1]={0};
            TLV tlv(TASK_GET_PLAYBACK_RANGE_ERROR,0,value);
            string msg(reinterpret_cast<char *>(&tlv),8+0);
            _conn.sendInLoop(msg);

        }
        SQLConn.dump(data);
        json j_array=json::array();
        vector<string> fieldNames = {"start_time","end_time"};
        for(int i = 1;i<(int)data.size();++i){
            json obj = json::object();
            for(int j = 0;j<(int)data[0].size();++j){
                obj[fieldNames[j]] = data[i][j];//把微秒变成毫秒
                cout<<"json_object: "<<obj[fieldNames[j]]<<endl;
            }
            j_array.push_back(obj);
        }
        TLVPacket tlv(TASK_GET_PLAYBACK_RANGE_OK,j_array.dump().c_str());
        vector<uint8_t> sdv = tlv.serialize();
        _conn.sendInLoop(string((const char * )sdv.data(),sdv.size()));
        LOG_DEBUG(string("send ranage is successful.").c_str());
    }
}


void SendPlayBackCodecParams::process(void *ptr){
    if(is_valid_json(_packet._msg)==1){
        json j =json::parse(_packet._msg);
        LOG_INFO(_packet._msg.c_str());
        int camera_id = j["camera_id"].get<int>();
        int channel = j["channel"].get<int>();
        //查找数据库中对应的数据
        char sql[256]={0};
        sprintf(sql,"SELECT name  FROM record_file WHERE camera_id = %d AND channel = %d",camera_id,channel);
        LOG_DEBUG(sql);
        MySQLClient SQLConn;
        vector<vector<string>> data = SQLConn.readOperationQuery(sql);
        if(data.size()<2){
            char value[1]={0};
            TLV tlv(TASK_GET_CODEC_PARAMS_RESP_ERROR,0,value);
            string msg(reinterpret_cast<char *>(&tlv),8+0);
            _conn.sendInLoop(msg);

        }
    pair<string,string> pair_string  = RtspDecoder::get_playback_decoder_parameters(data[1][0]); 
    TLVPacket tlv( TASK_GET_CODEC_PARAMS_RESP_OK,pair_string.first);
    vector<uint8_t> st_data = tlv.serialize();
    _conn.sendInLoop(string((const char *)st_data.data(),st_data.size()));
    TLVPacket atlv( TASK_GET_AUDIO_CODEC_PARAMS_RESP_OK,pair_string.second);
    vector<uint8_t> ast_data = atlv.serialize();
    _conn.sendInLoop(string((const char *)ast_data.data(),ast_data.size()));
    }
}

void SendPlayBackAVPacket::process(void *ptr){
    int fd = _conn.fd();
    if(is_valid_json(_packet._msg)==1){
        json j =json::parse(_packet._msg);
        LOG_INFO(_packet._msg.c_str());
        long start_time = j["start_time"].get<long>()*1000;
        long end_time = j["end_time"].get<long>()*1000;
        int camera_id = j["camera_id"].get<int>();
        int channel = j["channel"].get<int>();
        //查找数据库中对应的数据
        _rtspd->run(_conn,camera_id,channel,start_time,end_time);
    }

    if(_ffmpegs.count(fd)>0)
    _ffmpegs.erase(fd);
}

void SendStm32Infm::process(void * ptr){
    for(auto & elem :users->getUsers()){
        TLVPacket tlv(_packet._type,_packet._msg);
        vector<uint8_t> value = tlv.serialize();
       elem.second._channel->sendInLoop(string((const char * )value.data(),value.size()));
    }
}


